﻿#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
//day10
//x 1 --> 32
// -1在内存中的补码全是1  x = x & (x - 1) 表达式执行一次就会将x的2进制中最右边的一个1去掉
// 位操作都是对补码进行操作。
// 
//1、求函数返回值，传入 - 1 ，则在64位机器上函数返回（ ）
//int func(int x)
//{
//	int count = 0;
//	while (x)
//	{
//		count++;
//		x = x & (x - 1);//与运算
//	}
//	return count;
//}



//x 2 --> 死循环 ***×*** 此题一个关键，有符号数右移运算高位是补符号位的，
//				负数的符号位是1，所以x永远不会变为0，是个死循环
// 11111111 11111111 11111111 11111111
// 11111111 11111111 11111111 11111111
//2、读代码选结果（ ）
//int count = 0;
//int x = -1;
//while (x)
//{
//	count++;
//	x = x >> 1;
//}
//printf("%d", count);



//x 3  --> C  ***×***
// a/b 是表达式，表达式计算结果是一个值不能做左值
//3、下述赋值语句错误的是（ ）
//A : a = (b = (c = 2, d = 3)) B : i++ C : a / b = 2 D : a = a < a + 1



//x 4 --> A       w < x ? w : (y < z ? y : z)
//4、若有 int w = 1, x = 2, y = 3, z = 4; 则条件表达 w < x ? w : y < z ? y : z 的值是（ ）
//A : 1 B : 2 C : 3 D : 4



//x 5 --> 0 0 ***×***   0 1是错的 先执行n=b<a部分，其中，关系运算符优先级高于赋值运算符，所以先算
//	b < a，得到0，n = 0赋值运算的结果将作为括号内表达式的结果，即(n = b < a) && (m = a)转换成(0) && (m = a)，
// && 运算前表达式为假，则后面的括号(m = a)不运算，m值还是0，最后，&& 的结果是0，即k = 0
// 
//  &&运算前面为假后面不运算 ，|| 前面为真后面不运算
//5、以下程序运行后的输出结果是（ ）
//int main()
//{
//	int a = 1, b = 2, m = 0, n = 0, k;
//	k = (n = b < a) && (m = a);
//	printf("%d,%d\n", k, m);  //0  1
//	return 0;
//}





//b 1
//JZ65 不用加减乘除做加法
//描述
//写一个函数，求两个整数之和，要求在函数体内不得使用 + 、 - 、 * 、 / 四则运算符号。
//数据范围：两个数都满足 −10≤n≤1000−10≤n≤1000
//进阶：空间复杂度 O(1)O(1)，时间复杂度 O(1)O(1)
//输入：1, 2
//返回值：3
//https://www.nowcoder.com/practice/59ac416b4b944300b617d4f7f111b215?tpId=13&tqId=23249&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

//可以考虑十进制。 如19 + 8   不考虑进位相加 19+8=17  相加的进位 十进制一位 10  17+10=27 加完后 减去1(01)左移一次(10) 10变成00 结束
//				   如46+85 不考虑进位相加 46+85=21 相加的进位 十位百位都有一个 110 先十进制
//				   21+10=31 110减去一位(01左移一次 10) 110-10=100 ；然后 31+100=131 100减去第二位(01左移两次 100) 100-100=0 结束

//二进制相加思想：与十进制相同，先计算不考虑进位的相加结果（ 0 + 0 得 0 ， 1 + 1 进位得 0 ， 1 + 0 得 1 ），使用异
//或可以取得； 然后计算相加的进位结果（同 1 的位置左移一位即可），使用相与后左移取得。
//示例：
//5 0101 + 7 0111
//不考虑进位的相加结果 0101 ^ 0111 -> 0010
//相加的进位 0101 & 0111 -> 0101 因为进位左移得到 1010
//1010 + 0010
//不考虑进位的相加结果 1010 ^ 0010 -> 1000
//相加的进位 1010 & 0010 -> 0010 因为进位左移得到 0100
//1000 + 0100
//不考虑进位的相加结果 1000 ^ 0100 -> 1100
//相加的进位 1000 & 0100 -> 0000 进位为0结束运算
/*
* @param num1 int整型
* @param num2 int整型
* @return int整型
*/
//int Add(int num1, int num2)
//{
//    while (num2 != 0)
//    {
//        int tmp = num1 ^ num2;  //不考虑进位相加的结果 如果不用tmp记录
//        num2 = (num1 & num2) << 1; //后面num1的值会先改变
//        num1 = tmp;
//    }
//    return num1;
//}




//b 2
//448. 找到所有数组中消失的数字
//给你一个含 n 个整数的数组 nums ，其中 nums[i] 在区间[1, n] 内。
//请你找出所有在[1, n] 范围内但没有出现在 nums 中的数字，并以数组的形式返回结果。
//示例 1：
//输入：nums = [4, 3, 2, 7, 8, 2, 3, 1]
//输出：[5, 6]
//https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/
 //一般的方法，假设1~n中 1没出现 令i=1~n,去遍历，不存在就存到返回数组中
 //方法二   取绝对值函数abs
#include <stdlib.h>
//int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
//{
//    int i = 0;
//    for (i = 0; i < numsSize; i++)
//    {
//        if (nums[abs(nums[i]) - 1] > 0) //不然可能负数变正数
//            nums[abs(nums[i]) - 1] = -nums[abs(nums[i]) - 1];//取相反数的操作
//    }
//    int* ret = (int*)malloc(sizeof(int) * (numsSize));
//    *returnSize = 0;
//    for (i = 0; i < numsSize; i++)
//    {
//        if (nums[i] > 0)
//        {
//            ret[*returnSize] = i + 1;
//            *returnSize += 1;
//        }
//    }
//    return ret;
//}




//day 11

//x1 --> double  ***×*** 算数转换向上转化
// char int long float double运算的时候是从低转到高的，表达式的类型会自动提升或者转换为参与表达式求值的最上级类型
//1、声明以下变量，则表达式: ch / i + (f * d – i) 的结果类型为（ ）
//char ch;
//int i;
//float f;
//double d;



//x 2 --> A   因为实际上会发生隐式转换， int 会变成 unsigned int 都是1
//2、关于代码的说法正确的是（ ）
//int main()
//{
//	int x = -1;
//	unsigned int y = 2;
//	if (x > y)
//	{
//		printf("x is greater");
//	}
//	else
//	{
//		printf("y is greater");
//	}
//	return 0;
//}
//A : x is greater B : y is greater C : 依赖实现 D : 随机


//x 3 --> A 取余两边必须是整数   D中a=0  a = a + (a = a - (a = 9))应该是这样吧
//3、已知有如下各变量的类型说明，则以下不符合C语言语法的表达式是（ ）
//int k, a, b;
//unsigned int w = 5;
//double x = 1.42;
//A: x % 3 B : w += -20 C : k = (a = 200, b = 300) D : a += a -= a = 9
//int main()
//{
//	int a;
//	a += a -= a = 9;
//	return 0;
//}



//x 4 --> C  运算都是补码   左移31位 10000000 00000000 00000000 00000000  int表示的是-2147483648
//负数右移符号位不变		右移31位 11111111 11111111 11111111 11111111  是-1
//									 00000000 00000000 00000000 00000001
//									 11111111 11111111 11111111 11111110
//							取反+1   10000000 00000000 00000000 00000010  是-2
//4、下面函数的输出结果是（ ）
//void func()
//{
//int k = 1 ^ (1 << 31 >> 31);
//printf("%d\n", k);
//}
//A : 0 B : -1 C : -2 D : 1



//x 5 --> A   编译后 运行
// 一般表达式的运算是在运行时执行的，而sizeof是一个编译阶段就执行的运算符，在其内的任何运算都不执行，只推测出其中
//表达式结果的类型求其大小，故前后i的值不变。
//5、如下代码的输出结果是（ ）
//int main()
//{
//	int i = 1;
//	sizeof(i++);
//	printf("%d\n", i);
//	return 0;
//}
//A : 1 B : 4 C : 2 D : 8



//二、编程题
//485. 最大连续 1 的个数
//给定一个二进制数组 nums ， 计算其中最大连续 1 的个数。
//示例 1：
//输入：nums = [1, 1, 0, 1, 1, 1]
//输出：3
//解释：开头的两位和最后的三位都是连续 1 ，所以最大连续 1 的个数是 3.
//https://leetcode.cn/problems/max-consecutive-ones/
//int findMaxConsecutiveOnes(int* nums, int numsSize)
//{
//    int i = 0;
//    int count = 0; int tmp = 0;
//    for (i = 0; i < numsSize; i++)
//    {
//        if (nums[i] == 1)
//        {
//            count++;
//            if (count > tmp)
//                tmp = count;
//        }
//        else
//        {
//            count = 0;
//        }
//    }
//    return tmp;
//}

//方法二
//int findMaxConsecutiveOnes(int* nums, int numsSize)
//{
//    int i = 0;
//    int max_count = 0; int cur_count = 0;
//    for (i = 0; i < numsSize; i++)
//    {
//        if (nums[i] == 1)
//        {
//            cur_count++;
//            max_count = max_count > cur_count ? max_count : cur_count;
//        }
//        else
//        {
//            cur_count = 0;
//        }
//    }
//    return max_count;
//}

//方法2.1
// int findMaxConsecutiveOnes(int* nums, int numsSize)
// {
//     int i = 0;
//     int max_count = 0;int cur_count = 0;
//     for(i=0; i<numsSize; i++)
//     {
//         if(nums[i] == 1)
//         {
//             cur_count++;
//         }
//         else
//         {
//             max_count = max_count > cur_count? max_count:cur_count;
//             cur_count = 0;
//         }
//     }
//     //不然最后一次最大值可能出现在cur_count上
//     max_count = max_count > cur_count?max_count:cur_count; 
//     return max_count;
// }




//b 2
// HJ56 完全数计算 
//完全数（Perfect number），又称完美数或完备数，是一些特殊的自然数。
//它所有的真因子（即除了自身以外的约数）的和（即因子函数），恰好等于它本身。
//例如：28，它有约数1、2、4、7、14、28，除去它本身28外，其余5个数相加，1 + 2 + 4 + 7 + 14 = 28。
//输入n，请输出n以内(含n)完全数的个数。
//数据范围： 1≤n≤5×105 1≤n≤5×105
//输入描述：
//输入一个数字n
//输出描述：
//输出不超过n的完全数的个数
//输入：1000
//输出：3
//https://www.nowcoder.com/practice/7299c12e6abb437c87ad3e712383ff84?tpId=37&&tqId=21279&rp=1&ru=/ta/huawei&qru=/ta/huawei/question-ranking

//int main()
//{
//    int n = 0;
//    scanf("%d", &n);
//    int count = 0; int i = 0; 
//    for (i = 2; i <= n; i++)
//    {
//        int j = 0; int sum = 0;
//        for (j = 1; j <= i / 2; j++)   //用开平方也是一样的
//        {
//            if (i % j == 0)
//            {
//                sum += j;
//            }
//        }
//        if (sum == i)
//            count++;
//    }
//    printf("%d\n", count);
//}


//方法二 还有更快的  28/2 = 14 2和14都是28的约数，14就不要再算了
#include<math.h>
int is_perfect_num(int n)
{
    int sum = 1;
    int i = 0;
    for (i = 2; i <= sqrt(n); i++) //i改成2 可以少算一次i=1时候的情况
    {
        if (n % i == 0) //判断是否能够整除i，能整除则i和结果都是约数
        {
            sum += i;      // ↓防止在除数和结果相同的情况下还加
            if (i != sqrt(n)) // 14/14=0 加一次就可以了
                sum += n / i;
        }
    }
    if (sum == n)
        return 1;
    return 0;
}
int main()
{
    int count = 0;
    int i = 0; int n = 0;
    scanf("%d", &n);
    for (i = 2; i <= n; i++)  //1不参与判断
    {
        if (is_perfect_num(i))
            count++;
    }
    printf("%d\n", count);
    return 0;
}





//day12
// 
//x1 --> A    
// '0' <= c <= '9' 注意 是先比较 '0' <= c  结果是真值1(以%c打印是个方块噢) 而不是ASCLL值
//1、请阅读以下程序，其运行结果是（ ）
//int main()
//{
//	char c = 'A';
//	//char a = ('0' <= c);
//	if ('0' <= c <= '9') printf("YES");
//	else printf("NO");
//	//printf("%d", a);
//	return 0;
//}
//A: YES B : NO C : YESNO D : 语句错误


//x 2 -->A                 1111 1111 1111 1010  因为最高位不是符号位
// 无符号整型提升 0 0 0 0  1111 1111 1111 1010  如果是short 最高位是符号位 整型提升也要升符号位
//2、假设编译器规定 int 和 short 类型长度分别为32位和16位，若有下列C语言语句，则 y 的机器数为（ ）
//unsigned short x = 65530;
//unsigned int y = x;
//A: 0000 7FFA B : 0000 FFFA C : FFFF 7FFA D : FFFF FFFA


//x 3 --> 0
//3、下列程序的输出结果是什么（ ）   ans的输出规律是 1 3 3 2 0 0
//int main()
//{
//    int n = 1001;
//    int ans = 0;
//    for (int i = 1; i <= n; ++i)
//    {
//        ans ^= i % 3;
//    }
//    printf("%d", ans);
//    return 0;
//}
//A: -2 B : 0 C : 1 D : 2